package com.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.common.api.ApprovalApi;
import com.common.core.domain.AjaxResult;
import com.common.core.domain.entity.ProcessConfig;
import com.common.core.domain.entity.SysUser;
import com.common.core.service.ProcessConfigService;
import com.common.utils.CurrentRoleUtils;
import com.common.utils.QueryWrapperUtils;
import com.common.utils.SecurityUtils;
import com.common.utils.StringUtils;
import com.common.utils.bean.BizProcessMessages;
import com.common.utils.bean.ReflectionUtils;
import com.common.utils.uuid.IdUtils;
import com.domain.bo.EthicalReviewBo;
import com.domain.entity.EthicalReview;
import com.domain.vo.EthicalListVo;
import com.domain.vo.NavigationVo;
import com.flowable.domain.vo.FlowQueryVo;
import com.flowable.domain.vo.task.BpmTaskApproveReqVO;
import com.flowable.service.IFlowTaskService;
import com.mapper.EthicalReviewMapper;
import com.service.IEthicalReviewService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class EthicalReviewImpl implements IEthicalReviewService {

    @Autowired
    private EthicalReviewMapper ethicalReviewMapper;

    @Autowired
    private ResearchServImpl researchServ;

    //发起流程
    @Autowired
    private ApprovalApi approvalApi;

    //流程引擎
    @Autowired
    private IFlowTaskService flowTaskService;

    //流程配置
    @Autowired
    private ProcessConfigService processService;

    /**
     * 左上角根据状态的数量统计
     * @param ethicalReviewBo
     * @return
     */
    public List<NavigationVo.NameAndCount> selectGroups(EthicalReviewBo ethicalReviewBo){
        List<NavigationVo.NameAndCount> res = new ArrayList<>();
        try{
            QueryWrapper<NavigationVo.NameAndCount> queryWrapper = new QueryWrapper<>();
            queryWrapper = this.getCondition(queryWrapper,ethicalReviewBo,"group");//拼条件
            QueryWrapperUtils.getParamsEthicalBusiness(queryWrapper,SecurityUtils.getLoginUser().getUser(),"ethical");//用户权限

            res = ethicalReviewMapper.selectGroups(queryWrapper,ethicalReviewBo);
        }catch (Exception exception){
            res = null;
        }
        return res;
    }

    /**
     * 查询伦理审查列表
     *
     * @param ethicalReviewBo 伦理审查
     * @param operateType
     * @return 伦理审查
     */
    @Override
    public IPage<EthicalListVo> selectList(EthicalReviewBo ethicalReviewBo,String operateType){
        IPage<EthicalListVo> res = new Page<>();
        try{
            QueryWrapper<EthicalListVo> queryWrapper = new QueryWrapper<>();
            queryWrapper = this.getCondition(queryWrapper,ethicalReviewBo,"list");//拼条件
            QueryWrapperUtils.getParamsEthicalBusiness(queryWrapper,SecurityUtils.getLoginUser().getUser(),"ethical");//用户权限

            if(operateType.equals("list")){
                IPage<EthicalListVo> myPage = new Page<>(ethicalReviewBo.getPageNo(), ethicalReviewBo.getPageSize());
                res = ethicalReviewMapper.selectListInfos(myPage,queryWrapper,ethicalReviewBo);
                res = this.getCheckInfosForList(res,"伦理审查",EthicalListVo::setTaskId,EthicalListVo::setIsAuditor,EthicalListVo::getProcessInstanceId);
            }else{
                IPage<EthicalListVo> myPage = new Page<>(1, 1000);
                res = ethicalReviewMapper.selectListInfos(myPage,queryWrapper,ethicalReviewBo);
            }
        }catch (Exception exception){
            String ex = exception.getMessage();
        }
        return res;
    }

    /**
     * 拼条件
     * @param queryWrapper
     * @param ethicalReviewBo
     * @return
     */
    private QueryWrapper getCondition(QueryWrapper queryWrapper,EthicalReviewBo ethicalReviewBo,String funcType){
        try{
            //处理结项日期字段（年份4、年月7、年月日）
            String startAcceptTime = changeDateString(ethicalReviewBo.getStartTime(),"start");
            String endAcceptTime = changeDateString(ethicalReviewBo.getEndTime(),"end");

            queryWrapper.like(StringUtils.isNotBlank(ethicalReviewBo.getName()),"zb.NAME",ethicalReviewBo.getName())
                    .like(StringUtils.isNotBlank(ethicalReviewBo.getChargerName()),"CHARGER_NAME",ethicalReviewBo.getChargerName())
                    .like(StringUtils.isNotBlank(ethicalReviewBo.getApplyer()),"APPLYER",ethicalReviewBo.getApplyer())
                    .ge(StringUtils.isNotBlank(startAcceptTime), "APPLY_TIME", startAcceptTime)
                    .le(StringUtils.isNotBlank(endAcceptTime), "APPLY_TIME", endAcceptTime);
            if(funcType.equals("list")){
                queryWrapper.eq(StringUtils.isNotBlank(ethicalReviewBo.getCheckstatusByGroup()), "zb.CHECKSTATUS", ethicalReviewBo.getCheckstatusByGroup());
            }

            return queryWrapper;
        }catch (Exception exception){
            return queryWrapper;
        }
    }

    /**
     * 获取伦理审查详细信息
     * @param ID
     * @return
     */
    public EthicalReview selectEthicalReviewByID(String ID){
        try{
            EthicalReview res = ethicalReviewMapper.selectById(ID);
            //处理文件
            if(res != null){
                res.setFileInfoList(researchServ.getFileInfos(res.getFileId()));
            }
            return res;
        }catch (Exception exception){
            return new EthicalReview();
        }
    }

    /**
     * 保存伦理审查
     * @param ethicalReview 伦理审查
     * @return 结果
     */
    public AjaxResult saveEthicalReview(EthicalReview ethicalReview){
        String ethicalReviewId = "";
        String processInstanceId = "";
        String currentRoleKey = CurrentRoleUtils.getCurrentRoleKey(); //当前角色

        if(ethicalReview != null){
            Integer submitType = ethicalReview.getSubmitType();
            String checkStatus = ethicalReview.getCheckstatus();
            String operateType = StringUtils.isNotBlank(ethicalReview.getID())?"edit":"add";
            if(submitType != null){
                switch (submitType){
                    case -1:{
                        //暂存：新建编辑都只保存信息，不做任何其他操作
                        if(!currentRoleKey.equals("biz_kycgly") || !StringUtils.isNotBlank(checkStatus)){
                            ethicalReview.setCheckstatus("-1");//科研管理员、秘书的暂存都不改状态
                        }
                        ethicalReviewId = this.saveInfos(ethicalReview,operateType);
                        return StringUtils.isNotBlank(ethicalReviewId)?ethicalReviewId.contains("失败")?AjaxResult.error(ethicalReviewId):AjaxResult.success(BizProcessMessages.SAVE_SUCCESS):AjaxResult.error(BizProcessMessages.SAVE_FAIL);
                    }
                    case 1:{
                        //提交（科研人员）：新建编辑均保存信息+发起流程
                        ethicalReview.setCheckstatus("1");
                        ethicalReview = ReflectionUtils.updateFields(ethicalReview, EthicalReview.class);
                        ethicalReviewId = this.saveInfos(ethicalReview,operateType);
                        if(StringUtils.isNotBlank(ethicalReviewId)){
                            if(ethicalReviewId.contains("失败")){
                                return AjaxResult.error(ethicalReviewId);
                            }else{
                                processInstanceId = approvalApi.businessEntryApproval(ethicalReviewId, "伦理审查");
                                if(!StringUtils.isNotBlank(processInstanceId)){
                                    //发起流程并返回示例id
                                    //保存成功但流程实例id为空 -> 发起流程失败
                                    ethicalReview.setCheckstatus("-1");
                                    this.saveInfos(ethicalReview,operateType);
                                    return AjaxResult.warn(BizProcessMessages.SAVE_PARTIAL_SUCCESS);
                                }else{
                                    return AjaxResult.success(BizProcessMessages.SAVE_SUCCESS);
                                }
                            }
                        }else{
                            return AjaxResult.error(BizProcessMessages.SAVE_FAIL);
                        }
                    }
                    case 2:{
                        //保存并通过（管理员）：审核中且是当前审核人-》调流程接口；直接通过-》实例id为0
                        if(operateType.equals("add") || operateType.equals("edit") && (!StringUtils.isNotBlank(checkStatus) || StringUtils.isNotBlank(checkStatus)&&!checkStatus.equals("1"))){
                            //审核状态是暂存*不通过 -》直接将实例id置为0
                            ethicalReview = ReflectionUtils.updateFields(ethicalReview, EthicalReview.class);
                            ethicalReview.setProcessInstanceId("0");
                            ethicalReview.setCheckstatus("2");
                            ethicalReviewId = this.saveInfos(ethicalReview,operateType);
                            return StringUtils.isNotBlank(ethicalReviewId)?ethicalReviewId.contains("失败")?AjaxResult.error(ethicalReviewId):
                                    AjaxResult.success(BizProcessMessages.SAVE_SUCCESS):AjaxResult.error(BizProcessMessages.SAVE_FAIL);
                        }else{
                            //审核状态为审核中且是当前审核人（审核人逻辑前端处理）：保存并调流程接口
                            try{
                                ethicalReviewId = this.saveInfos(ethicalReview,operateType);
                                if(StringUtils.isNotBlank(ethicalReviewId)){
                                    BpmTaskApproveReqVO bta = new BpmTaskApproveReqVO();
                                    bta.setId(ethicalReview.getTaskId());
                                    bta.setReason(SecurityUtils.getNickName() + "保存并通过");
                                    flowTaskService.approveTask(SecurityUtils.getUserId(), bta);
                                    return AjaxResult.success(BizProcessMessages.SAVE_SUCCESS);
                                }else{
                                    return AjaxResult.error(BizProcessMessages.SAVE_FAIL);
                                }
                            }catch (Exception exception){
                                return AjaxResult.warn(BizProcessMessages.SAVE_SUCCESS_APPROVE_FAIL);
                            }

                        }
                    }
                    default: return AjaxResult.error(BizProcessMessages.SAVE_FAIL);
                }
            }else{
                ethicalReview.setCheckstatus("-1");
                ethicalReviewId = this.saveInfos(ethicalReview,operateType);
                return StringUtils.isNotBlank(ethicalReviewId)?AjaxResult.success(BizProcessMessages.SAVE_SUCCESS):AjaxResult.error(BizProcessMessages.SAVE_FAIL);
            }
        }else{
            return AjaxResult.warn("未获取到伦理审查信息！");
        }
    }

    /**
     * 保存伦理审查（业务处理）
     * @param ethicalReview
     * @param operateType
     * @return
     */
    public String saveInfos(EthicalReview ethicalReview,String operateType){
        String res = "";

        SysUser loginUser = SecurityUtils.getLoginUser().getUser();
        Date date = new Date();
        SimpleDateFormat dateFormat= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        String ethicalId = ethicalReview.getID();

        try{
            int saveRes = 0;
            ethicalReview.setLasteditdate(dateFormat.parse(dateFormat.format(date)));
            ethicalReview.setLasteditusername(loginUser.getNickName());
            ethicalReview.setLastedituserid(loginUser.getUserRealId());

            if(operateType.equals("add")){
                ethicalReview.setCreatedate(dateFormat.parse(dateFormat.format(date)));
                ethicalReview.setCreateuserid(loginUser.getUserRealId());
                ethicalReview.setCreateusername(loginUser.getNickName());

                ethicalId = IdUtils.simpleUUID();
                ethicalReview.setID(ethicalId);
                saveRes = ethicalReviewMapper.insert(ethicalReview);
            }else{
                saveRes = ethicalReviewMapper.updateById(ethicalReview);
            }

            if(saveRes > 0){
                res = ethicalId;
            }
        }catch (Exception exception){
            String ex = exception.getMessage();
        }

        return res;
    }

    /**
     * 批量删除伦理审查
     * @param IDs 需要删除的伦理审查主键集合
     * @return 结果
     */
    public String deleteEthicalReviewByIDs(String[] IDs){
        String res = "操作成功！";
        try{
            List<String> idList = Arrays.stream(IDs).collect(Collectors.toList());
            idList.forEach(id->{
                ethicalReviewMapper.deleteById(id);
            });
        }catch (Exception exception){
            res = "操作失败！" + exception.getMessage();
        }
        return res;
    }

    /**
     *
     * @param oldPage
     * @param moduleName
     * @param setTaskId
     * @param setIsAuditor
     * @param getProcessInstanceId
     * @param <T>
     */
    public <T> IPage<T> getCheckInfosForList(IPage<T> oldPage, String moduleName, BiConsumer<T,String> setTaskId, BiConsumer<T,Boolean> setIsAuditor,
                                             Function<T,String> getProcessInstanceId){
        try{
            List<T> oldList = oldPage.getRecords();
            if(oldList != null && oldList.size()>0){
                //获取当前用户所有的代办列表
                ProcessConfig processConfig = processService.getProcessByModelName(moduleName);
                FlowQueryVo queryVo = new FlowQueryVo();
                queryVo.setProcessDefinitionKey(processConfig.getProcessKey());
                // 获取流程任务列表,Map<instanceId, taskId>
                Map<String, String> instanceTaskMap = flowTaskService.todoListBydefKey_Api(queryVo);
                for(T obj:oldList){
                    String processInstanceId = getProcessInstanceId.apply(obj);//获取流程实例ID
                    if(StringUtils.isNotEmpty(processInstanceId) && instanceTaskMap.containsKey(processInstanceId)){
                        setTaskId.accept(obj,instanceTaskMap.get(processInstanceId));
                        setIsAuditor.accept(obj,true);
                    }else{
                        setIsAuditor.accept(obj,false);
                    }
                }

                oldPage.setRecords(oldList);
            }
        }catch (Exception exception){
            String ex = exception.getMessage();
        }

        return oldPage;
    }

    /**
     * 处理申请时间字符串
     * @param dateStr
     * @param startOrEnd
     * @return
     */
    public String changeDateString(String dateStr,String startOrEnd){
        if(StringUtils.isNotBlank(dateStr)){
            int strLength = dateStr.length();
            if(startOrEnd.equals("start")){
                if(strLength == 4){
                    dateStr = dateStr + "-01-01 00:00:00";
                }else if(strLength == 7){
                    dateStr = dateStr + "-01 00:00:00";
                }if(strLength == 10){
                    dateStr = dateStr + " 00:00:00";
                }
            }else{
                if(strLength == 4){
                    dateStr = dateStr + "-12-31 23:59:59";
                }else if(strLength == 7){
                    dateStr += "-01"; // 默认到每月的第一天
                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
                    LocalDate date = LocalDate.parse(dateStr, formatter);
                    LocalDate lastDayOfMonth = date.withDayOfMonth(date.lengthOfMonth());
                    DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
                    dateStr = lastDayOfMonth.format(outputFormatter) + " 23:59:59";
                }else if(strLength == 10){
                    dateStr = dateStr + " 23:59:59";
                }
            }
        }
        return dateStr;
    }
}
